﻿#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <corecrt_wstdio.h>

using namespace std;


#define PI 3.1415926
#define WIDTH 800
#define HEIGHT 600

float off_set_angle = PI / 6;
float shorten_rate = 0.65;
int show_animation = 1;

void startup();
void update();
void brunch(float x_start, float y_start, float length, float angle, float thickness, int generation);
float map_value(float input, float input_min, float input_max, float output_min, float output_max);
float rand_between(float min, float max);

int main()
{
	startup();

	while (!(_kbhit() && _getch() == 'q'))
	{
		update();
	}

	return 0;
}


void startup()
{
	srand(time(0));
	initgraph(WIDTH, HEIGHT);
	setbkcolor(WHITE);
	cleardevice();
	BeginBatchDraw();
	brunch(WIDTH / 2, HEIGHT, 0.45 * HEIGHT * shorten_rate, -PI / 2, 15 * shorten_rate, 1);
	FlushBatchDraw();
}


void update()
{
	MOUSEMSG m;
	
	if (MouseHit())
	{
		m = GetMouseMsg();
		if (m.uMsg == WM_MOUSEMOVE)
		{
			off_set_angle = map_value(m.x, 0, WIDTH, PI / 10, PI / 4);
			shorten_rate = map_value(m.y, 0, HEIGHT, 0.7, 0.3);
		}
		if (m.uMsg == WM_LBUTTONDOWN)
		{
			cleardevice();
			brunch(WIDTH / 2, HEIGHT, 0.45 * HEIGHT * shorten_rate, -PI / 2, 15 * shorten_rate, 1);
			FlushBatchDraw();
		}
		if (m.uMsg == WM_RBUTTONDOWN)
		{
			if (show_animation == 1)
			{
				show_animation = 0;
			}
			else if (show_animation == 0)
			{
				show_animation = 1;
			}
		}
	}
}


void brunch(float x_start, float y_start, float length, float angle, float thickness, int generation)
{
	float x_end = x_start + length * cos(angle);
	float y_end = y_start + length * sin(angle);

	setlinestyle(PS_SOLID, thickness);
	COLORREF color = HSVtoRGB(15, 0.75, 0.4 + generation * 0.05);
	setlinecolor(color);
	line(x_start, y_start, x_end, y_end);

	int child_generation = generation + 1;
	float child_length = shorten_rate * length;
	float left_child_length = child_length * rand_between(0.9, 1.1);
	float right_child_length = child_length * rand_between(0.9, 1.1);
	float centre_child_length = child_length * rand_between(0.8, 1.1);

	if (child_generation >= 2 && child_generation <= 9)
	{
		float child_thickness = thickness * 0.8;

		if (child_thickness < 2)
		{
			child_thickness = 2;
		}

		if (rand_between(0, 1) < 0.95)
		{
			brunch(x_end, y_end, left_child_length, angle + off_set_angle * rand_between(0.5, 1), child_thickness, child_generation);
		}
		if (rand_between(0, 1) < 0.95)
		{
			brunch(x_end, y_end, right_child_length, angle - off_set_angle * rand_between(0.5, 1), child_thickness, child_generation);
		}
		if (rand_between(0, 1) < 0.85)
		{
			brunch(x_end, y_end, centre_child_length, angle + off_set_angle / 5 * rand_between(-1, 1), child_thickness, child_generation);
		}
	}
	else
	{
		setlinestyle(PS_SOLID, 1);
		COLORREF color = HSVtoRGB(rand_between(300, 350), rand_between(0.2, 0.3), 1);
		setlinecolor(color);
		setfillcolor(color);

		if (child_length <= 4)
		{
			fillcircle(x_end, y_end, 2);
		}
		else
		{
			fillcircle(x_end, y_end, child_length / 2);
		}
	}
	if (show_animation)
	{
		FlushBatchDraw();
		Sleep(20);
	}
}


float map_value(float input, float input_min, float input_max, float output_min, float output_max)
{
	float output;
	if (abs(input - input_min) < 0.000001)
	{
		output = output_min;
	}
	else
	{
		output = (input - input_min) * (output_max - output_min) / (input_max - input_min) + output_min;
		return output;
	}
}


float rand_between(float min, float max)
{
	float t = rand() / double(RAND_MAX);
	float r = map_value(t, 0, 1, min, max);
	return r;
}